% Ejercicio "Matrices simétricas"
\subsection*{\fbox{\theejercicio} - Matrices sim\'etricas}

Se desea construir un programa para leer desde un fichero matrices sim\'etricas de n\'umeros enteros (positivos y negativos) escritas de forma triangular y realizar con ellas ciertas operaciones. El fichero de entrada contiene la matriz escrita por filas, separando cada n\'umero con espacios en blanco o tabuladores, y presentando solamente la diagonal inferior, por ejemplo, el fichero:

$$
\begin{array}{lccr}
100 &     &     &     \\
101 & 102 &     &     \\
103 & 104 & 105 &     \\
106 & 107 & 108 & 109 \\
\end{array}
$$

representa la matriz:

$$
\left[ \begin{array}{lccr}
100 & 101 & 103 & 106 \\
101 & 102 & 104 & 107 \\
103 & 104 & 105 & 108 \\
106 & 107 & 108 & 109 \\
\end{array}
\right]
$$

NOTA: Una matriz sim\'etrica es aquella igual que su traspuesta, es decir, se cumple $a[i,j]=a[j,i]$.

\smallskip

Se pide:

\smallskip

Dise\~nar una gram\'atica y escribir mediante LEX y YACC un analizador sint\'actico que sea capaz de leer matrices sim\'etricas escritas de esta forma, comprobar que tiene una estructura correcta, y calcular la suma de todos los elementos de la matriz.

% Solución del ejercicio
\subsubsection*{SOLUCI\'ON}

\underline{ESPECIFICACI\'ON LEX}:

\begin{verbatim}
%{
#include "main.h"
#include "y.tab.h"
%}

%%

[\ \t\r]+            { ; }
\n                   {
                       numlinea++;
                       return EOL;
                     }
[-+]?[1-9][0-9]*     {
                       yylval.valor = atoi(yytext);
                       return NUMERO;
                     }
                     {
                       char *st = (char*) malloc(100);
                       sprintf(st,"Caracter inesperado: %s",yytext);
                       yyerror(st);
                     }
%%
\end{verbatim}

\underline{ESPECIFICACI\'ON YACC}:

\begin{verbatim}
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "random.h"
#include "main.h"
%}

%union {
   int valor;
   struct {
      int  numElementos ;
      double  suma;
   } fila;
   struct {
      int  numFilas;
      int  numColumnas;
      double  suma;
   } matriz;
};

%type  <matriz>      Matriz
%type  <fila>        Fila

%token               EOL
%token <valor>       NUMERO

%%

Axioma: Matriz
        {
           if ($1.numFilas == $1.numColumnas) {
             printf("Matriz de %i x %i\nSuma de elementos= %f\n",
                     $1.numFilas, $1.numColumnas, $1.suma);
           } else {
             printf("ERROR\n");
           }
        }

Matriz: Matriz Fila
        {
           $$.numFilas = $1.numFilas + 1;
           if ($1.numColumnas+1 == $2.numElementos) {
               $$.numColumnas = $1.numColumnas + 1;
           } else {
               printf("La fila %i tiene %i elementos (numero de 
                       elementos incorrecto)\n", $$.numFilas,
                       $2.numElementos);
           }
           $$.suma = $1.suma + $2.suma;
        }
      | Fila
        {
           $$.numFilas = 1;
           if ($1.numElementos == 1) {
               $$.numColumnas = 1;
           } else {
               printf("La fila %i tiene %i elementos (numero de
                      elementos incorrecto)\n", $$.numFilas,
                      $1.numElementos);
           }
           $$.suma = $1.suma;
        }
      ;

Fila: NUMERO Fila
      {
        /* Este elemento no es de la diagonal */
        $$.numElementos = $2.numElementos +1;
        $$.suma = 2 * $1 + $2.suma;
      }
    | NUMERO EOL
      {
         /* Este es el elemento de la diagonal */
         $$.numElementos = 1;
         $$.suma = $1;
      }
    ;
\end{verbatim}

\underline{FICHERO main.h}:

\begin{verbatim}
#define yywrap() 1

extern char *nombreprograma;
extern char *nombrefichero;
extern int numlinea;
extern void yyerror(char *);
\end{verbatim}

\underline{FICHERO main.c}:

\begin{verbatim}
#include <stdio.h>

extern FILE *yyin;
extern FILE *yyout;

char *nombreprograma = NULL;
char *nombrefichero = NULL;
int numlinea=1;

extern void iniTipos();

/******************/
/* main           */
/******************/
main (int argc, char *argv[])
{
    void cerrarficheros ();
    int abrirficheros ();
    nombreprograma = argv[0];
    if (abrirficheros (argc,argv) == 1) { 
        yyparse();
    }
    cerrarficheros();
    return (1);
}

/******************/
/* abrirficheros  */
/* abre los ficheros de entrada/salida */
/* devuelve 0 en caso de error */
/******************/
abrirficheros (int argc, char **argv)
{
  if (argc > 3) { 
     printf ("Demasiados parametros.\n"); 
     return 0; 
  }
  if (argc > 1) { 
     nombrefichero = argv[1];
     yyin=fopen (argv[1], "r");
  }
  if (yyin == NULL) { 
     printf ("Fichero no encontrado.\n"); 
     return 0; 
  }
  if (argc > 2) { 
     yyout=fopen (argv[2], "w");
  }
  return 1;
}

/******************/
/* cerrarficheros */
/* cierra los ficheros de entrada/salida */
/******************/
void cerrarficheros () {fclose (yyin); fclose (yyout); return; }

/*******************************************************/
/* yyerror                                             */
/*******************************************************/
void yyerror(char *s)
{
    fprintf(stderr,"%s %s(%d): %s \n", nombreprograma, nombrefichero,
            numlinea,s);
}
\end{verbatim}

\underline{FICHERO Makefile}:

\begin{verbatim}
# Compilador

CC = gcc

# Flags

CFLAGS = -g

# Ficheros

PROG = matsim

HDRS = main.h

CSRCS = main.c

SRCS = $(CSRCS) \
       lex.yy.c \
       y.tab.c

OBJS = main.o \
       lex.yy.o \
       y.tab.o

.c.o:
       $(CC) -c $(CFLAGS) $*.c

#

$(PROG): $(OBJS)
   $(CC) $(CFLAGS) $(OBJS) -o $(PROG)

# Dependencias de los ficheros C

$(OBJS): $(HDRS)

# Dependencies de los ficheros de LEX y YACC

lex.yy.c: $(PROG).l y.tab.h
   lex $(PROG).l

y.tab.c y.tab.h: $(PROG).y
   yacc -d $(PROG).y

borrar:
   rm $(PROG) *.o y.tab.c y.tab.h lex.yy.c y.output
\end{verbatim}

